#ifndef _TBOX_H_
#define _TBOX_H_

#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>

#define TBOX_VERSION              "0.1.1"

/* copy from termbox2 */
#define TBOX_KEY_F1               (0xffff - 0)
#define TBOX_KEY_F2               (0xffff - 1)
#define TBOX_KEY_F3               (0xffff - 2)
#define TBOX_KEY_F4               (0xffff - 3)
#define TBOX_KEY_F5               (0xffff - 4)
#define TBOX_KEY_F6               (0xffff - 5)
#define TBOX_KEY_F7               (0xffff - 6)
#define TBOX_KEY_F8               (0xffff - 7)
#define TBOX_KEY_F9               (0xffff - 8)
#define TBOX_KEY_F10              (0xffff - 9)
#define TBOX_KEY_F11              (0xffff - 10)
#define TBOX_KEY_F12              (0xffff - 11)
#define TBOX_KEY_INSERT           (0xffff - 12)
#define TBOX_KEY_DELETE           (0xffff - 13)
#define TBOX_KEY_HOME             (0xffff - 14)
#define TBOX_KEY_END              (0xffff - 15)
#define TBOX_KEY_PGUP             (0xffff - 16)
#define TBOX_KEY_PGDN             (0xffff - 17)
#define TBOX_KEY_ARROW_UP         (0xffff - 18)
#define TBOX_KEY_ARROW_DOWN       (0xffff - 19)
#define TBOX_KEY_ARROW_LEFT       (0xffff - 20)
#define TBOX_KEY_ARROW_RIGHT      (0xffff - 21)
#define TBOX_KEY_BACK_TAB         (0xffff - 22)

#define TBOX_KEY_MOUSE_LEFT       (0xffff - 23)
#define TBOX_KEY_MOUSE_RIGHT      (0xffff - 24)
#define TBOX_KEY_MOUSE_MIDDLE     (0xffff - 25)
#define TBOX_KEY_MOUSE_RELEASE    (0xffff - 26)
#define TBOX_KEY_MOUSE_WHEEL_UP   (0xffff - 27)
#define TBOX_KEY_MOUSE_WHEEL_DOWN (0xffff - 28)

/* tbox align defines */
#define TBOX_ALIGN_FORWARD        0x0
#define TBOX_ALIGN_BACKWARD       0x1
#define TBOX_ALIGN_MIDDLE         0x2

/* common use */
#define TBOX_ALIGN_LEFT           TBOX_ALIGN_FORWARD
#define TBOX_ALIGN_RIGHT          TBOX_ALIGN_BACKWARD
#define TBOX_ALIGN_TOP            (TBOX_ALIGN_FORWARD << 0x4)
#define TBOX_ALIGN_BOTTOM         (TBOX_ALIGN_BACKWARD << 0x4)
#define TBOX_ALIGN_CENTER         ((TBOX_ALIGN_MIDDLE << 0x4) | TBOX_ALIGN_MIDDLE)

typedef int tbox_int_t; // pos width type
typedef struct tbox_widget tbox_widget_t;
typedef tbox_widget_t tbox_button_t;
typedef struct tbox_event tbox_event_t;

typedef enum {
    /* align: horizon, vertical */
    TBOX_ALIGN_LEFT_TOP = 0x00,
    TBOX_ALIGN_LEFT_BOTTOM,
    TBOX_ALIGN_LEFT_MIDDLE,
    TBOX_ALIGN_RIGHT_TOP = 0x10,
    TBOX_ALIGN_RIGHT_BOTTOM,
    TBOX_ALIGN_RIGHT_MIDDLE,
    TBOX_ALIGN_MIDDLE_TOP = 0x20,
    TBOX_ALIGN_MIDDLE_BOTTOM,
    TBOX_ALIGN_CENT,
} tbox_align_t;

typedef enum tbox_event_value {
    TBOX_EVENT_MOUSE_CLICK = 1,
    TBOX_EVENT_MOUSE_DOWN,
    TBOX_EVENT_MOUSE_UP,
    TBOX_EVENT_MOUSE_MOVEIN,
    TBOX_EVENT_MOUSE_MOVEOUT,
    TBOX_EVENT_MOUSE_WHEEL,
    TBOX_EVENT_KEY_UP,
    TBOX_EVENT_KEY_DOWN,
} tbox_event_value_t;

typedef enum tbox_status {
    TBOX_STATUS_OK = 0,
    TBOX_STATUS_EXIT,
} tbox_status_t;

typedef enum tbox_log_level {
    TBOX_LOG_FATAL = 0,
    TBOX_LOG_ERROR,
    TBOX_LOG_WARN,
    TBOX_LOG_INFO,
    TBOX_LOG_DEBUG,
} tbox_loglevel_t;

struct tbox_event {
    tbox_event_value_t ev; /* TBOX_EVENT_MOUSE_XXX */
    uint32_t key;
    int32_t x; /* mouse x */
    int32_t y; /* mouse y */
};

struct tbox_conf {
    /* log */
    enum tbox_log_level loglevel;
    char *logfile;

    /* callback */
    int (*on_resize)(int w, int h);
    int (*on_update)();
    int (*on_key)(uint32_t key);
};

struct tbox_widget {
    bool visible;
    bool focusable;
    bool fill_blank; // TODO: deprecated?
    bool show_border;
    bool text_wrap; // with this option `true`, tbox will do more

    /* inner text or widgets align, see TBOX_ALIGN_*. */
    uint8_t align;

    tbox_int_t x, y, w, h;

    /* text color */
    uint32_t bg;
    uint32_t fg;

    /* hint color */
    uint32_t hbg;
    uint32_t hfg;

    /* border and conner color */
    uint32_t bbg;
    uint32_t bfg;

    /* widget name, for trace only, won't be freed by tbox system */
    char *name;

    /* widget inner text and hint */
    int (*set_text)(tbox_widget_t *wi, char *text);
    int (*get_text)(tbox_widget_t *wi, char *text);
    //int (*set_hint)(tbox_widget_t *wi, char *text);

    /* set widget visible or not, add widget or del from event lists */
    int (*show)(tbox_widget_t *wi);
    int (*hide)(tbox_widget_t *wi);

    /* draw widget(s) immediately
     * update(): draw widget and inner widget
     * clean(): draw widget area with blank
     * */
    int (*update)(tbox_widget_t *wi);
    int (*clean)(tbox_widget_t *wi);

    /* widget mouse handler
     * see: TBOX_EVENT_MOUSE_XXX
     * */
    int (*on_mouse)(tbox_widget_t *wi, tbox_event_t *ev);

    /* widget focus handler */
    int (*on_focus)(tbox_widget_t *wi, bool got);

    /* user data */
    union {
        void *ptr;
        int num;
        uint32_t u32;
        uint64_t u64;
    } data;

    void *private_data;

    /* margin:
     * padding:
     * */
    tbox_int_t margin[4]; // TODO: tbox_ssize_t, remove longname
    tbox_int_t padding[4];

    /* conner and border style */
    // uint32_t conner[4];
    // uint32_t border[4];

    /* widget layout
     * Five directions: Left, Right, Top, Bottom, Inner(as a container).
     * */
    tbox_widget_t *layout[5];

    /* tbox private data defines */
    // TODO: saving memory...
    struct {
        bool deadloop;
        struct {
            tbox_int_t w, h;
        } hide;
        char *text;
        int text_bufsize;
    } _data;
};

int tbox_init(struct tbox_conf *conf);
void tbox_exit(void);
int tbox_poll(void);
int tbox_width(void);
int tbox_height(void);
int tbox_clear();
int tbox_show();

void tbox_print(const char *str, int x, int y, uint32_t fg, uint32_t bg);
char *tbox_nprint(char *str, int x, int y, int n, uint32_t fg, uint32_t bg);
// TODO: tbox_printf, tbox_nprintf

void tbox_log(int level, const char *fmt, ...);

void tbox_layout_add(tbox_widget_t *wi);

tbox_button_t *tbox_button(int width, int height, char *text);
tbox_button_t *tbox_box(int width, int height, bool fill_blank);
int tbox_setbuf(tbox_widget_t *wi, char *buf, int bufsize);
bool tbox_focus(tbox_widget_t *wi, bool enable);
tbox_widget_t *tbox_focus_next(tbox_widget_t *wi, uint8_t directions);
// TODO: inputbox, line

#endif
